#ifndef __SEMAPHORE_BULIDER_HPP__
#define __SEMAPHORE_BULIDER_HPP__
#include <iostream>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <string>
#include <semaphore.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <memory>
#include <vector>
#include <cstring>

const std::string defaultfile_name = "/tmp";
const int defaultproj_id = 0x34;
const int defaultperm = 0666;
const int defaultnum = 1;

const int SEM_CRAEY = IPC_CREAT | IPC_EXCL;
const int SEM_GET = IPC_CREAT;

// 产品类
class Semaphore
{
    void PV(int pos, int flag)
    {
        struct sembuf sem_b;
        sem_b.sem_num = pos;
        sem_b.sem_op = flag;
        sem_b.sem_flg = SEM_UNDO;
        int n = semop(semid_, &sem_b, 1);
        if(n < 0)
        {
            std::cerr << "semop error" << " , int file : " << __FILE__ << " , int line : " << __LINE__ << std::endl;
            exit(4);
        }
    }

public:
    Semaphore(int semid , int flag)
        : semid_(semid) , flag_(flag)
    {
    }

    void P(int pos)
    {
        PV(pos, -1);
    }

    void V(int pos)
    {
        PV(pos, 1);
    }

    int Get_id()   // 获取信号量id
    {
        return semid_;
    }

    ~Semaphore()
    {
        if(flag_ == SEM_CRAEY) // 只有创建信号量的semid才需要删除
        {
            semctl(semid_, 0, IPC_RMID);
            std::cout << "semaphore remove success" << std::endl;
        }
    }

private:
    int semid_;
    int flag_;
};

// 抽象建造者
class Bulider
{
public:
    // 设置key值的参数
    virtual Bulider &Set_Key(const std::string &file_name, const int &proj_id) = 0;
    // 创建key值
    virtual int Build_Key() = 0;

    // 构建权限
    virtual Bulider &Set_Perm(const int &perm) = 0;
    // 信号集中信号的个数
    virtual Bulider &Set_Num(const int &num) = 0;
    // 设置初始值
    virtual Bulider &Set_Value(const std::vector<int> &value) = 0;

    // 初始化信号量
    virtual void Init_EachSem(int pos, int value) = 0;
    // 初始化信号集
    virtual void Init_ALLSem() = 0;
    // 构建函数
    virtual void Create_Sem(int flag) = 0;
    // 获取信号量
    virtual std::shared_ptr<Semaphore> Get_Sem() = 0;

protected:
    std::string file_name_ = defaultfile_name;
    int proj_id_ = defaultproj_id;
    key_t key_;

    int perm_ = defaultperm;
    int num_ = defaultnum;
    std::vector<int> value_;
    std::shared_ptr<Semaphore> sem_;
};

// 具体的建造者
class SemaphoreBulider : public Bulider
{
public:
    SemaphoreBulider() = default;
    // 设置key值的参数
    virtual Bulider &Set_Key(const std::string &file_name, const int &proj_id) override
    {
        file_name_ = file_name;
        proj_id_ = proj_id;
        return *this;
    }

    // 创建key值
    virtual int Build_Key()
    {
        int k = ftok(file_name_.c_str(), proj_id_);
        std::cout << "file_name : " << file_name_ << " , proj_id : " << proj_id_ << " , key : " << k << std::endl;
        if (k < 0)
        {
            std::cerr << "ftok error" << " , int file : " << __FILE__ << " , int line : " << __LINE__ << std::endl;
            exit(1);
        }
        return k;
    }

    // 构建权限
    virtual Bulider &Set_Perm(const int &perm)
    {
        perm_ = perm;
        return *this;
    }
    // 信号集中信号的个数
    virtual Bulider &Set_Num(const int &num)
    {
        num_ = num;
        return *this;
    }
    // 设置初始值
    virtual Bulider &Set_Value(const std::vector<int> &value)
    {
        value_ = value;
        return *this;
    }

    // 初始化信号量
    virtual void Init_EachSem(int pos, int value)
    {
        union semun
        {
            int val;               /* Value for SETVAL */
            struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
            unsigned short *array; /* Array for GETALL, SETALL */
            struct seminfo *__buf; /* Buffer for IPC_INFO
                                      (Linux-specific) */
        };
        union semun arg;
        arg.val = value;
        int semid = sem_->Get_id();
        int n = semctl(semid, pos, SETVAL, arg);
        if (n < 0)
        {
            std::cerr << "semctl error" << " , int file" << __FILE__ << " , int line" << __LINE__ << std::endl;
            exit(3);
        }
    }

    // 初始化信号集
    virtual void Init_ALLSem()
    {
        // 一个个的进行初始化
        if (value_.size() != num_)
        {
            value_.resize(num_ , 1);
        }
        for (int i = 0; i < num_; i++)
        {
            Init_EachSem(i, value_[i]);
        }
    }

    // 构建函数,不进行初始化
    virtual void Create_Sem(int flag)
    {
        key_ = Build_Key();
        int _flag = flag;

        if(flag == SEM_CRAEY) flag |= perm_;

        // 创建信号集
        int semid = semget(key_, num_, flag);
        if (semid < 0)
        {
            std::cerr << "semget error" << " , int file : " << __FILE__ << " , int line : " << __LINE__ << std::endl;
            exit(2);
        }

        sem_ = std::make_shared<Semaphore>(semid , _flag);
    }
    // 获取信号量
    virtual std::shared_ptr<Semaphore> Get_Sem()
    {
        return sem_;
    }
};

// 构建指挥者
class Director
{
public:
    void Construct(Bulider &bulider, int flag)
    {
        bulider.Create_Sem(flag);
        if (flag == SEM_CRAEY) // 要进行初始化
        {
            bulider.Init_ALLSem();
        }
    }

private:
};

#endif